/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2025-06-10     Administrator       the first version
 */
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
#include "st7735s.h"


// 延时函数 (根据实际时钟频率调整)
static void lcd_delay_us(uint32_t us) {
    rt_hw_us_delay(us);
}

// GPIO模拟SPI写一个字节
static void lcd_spi_write_byte(uint8_t dat) {
    rt_pin_write(LCD_CS_PIN, PIN_LOW);

    for (uint8_t i = 0; i < 8; i++) {
        rt_pin_write(LCD_SCL_PIN, PIN_LOW);
        lcd_delay_us(1);

        // 高位在前
        rt_pin_write(LCD_SDA_PIN, (dat & 0x80) ? PIN_HIGH : PIN_LOW);
        dat <<= 1;

        rt_pin_write(LCD_SCL_PIN, PIN_HIGH);
        lcd_delay_us(1);
    }

    rt_pin_write(LCD_CS_PIN, PIN_HIGH);
}

// 发送命令
static void lcd_write_cmd(uint8_t cmd) {
    rt_pin_write(LCD_DC_PIN, PIN_LOW);
    lcd_spi_write_byte(cmd);
}

// 发送数据
static void lcd_write_data(uint8_t dat) {
    rt_pin_write(LCD_DC_PIN, PIN_HIGH);
    lcd_spi_write_byte(dat);
}

// 发送16位数据
static void lcd_write_data_16bit(uint16_t dat) {
    rt_pin_write(LCD_DC_PIN, PIN_HIGH);
    lcd_spi_write_byte(dat >> 8);
    lcd_spi_write_byte(dat & 0xFF);
}

// 初始化序列
static const uint8_t init_cmds[] = {
    // 软件复位
    0x01, 0x80, 120,
    // 睡眠模式关闭
    0x11, 0x80, 120,
    // 颜色模式设置 (16位RGB565)
    0x3A, 1, 0x05,
    // 显示反转设置 (行/列反转)
    0xB4, 1, 0x00,
    // 显示开
    0x29, 0x80, 120,
};

// 初始化LCD
static void lcd_init(void) {
    // 初始化GPIO
    rt_pin_mode(LCD_SCL_PIN, PIN_MODE_OUTPUT);
    rt_pin_mode(LCD_SDA_PIN, PIN_MODE_OUTPUT);
    rt_pin_mode(LCD_DC_PIN, PIN_MODE_OUTPUT);
    rt_pin_mode(LCD_RES_PIN, PIN_MODE_OUTPUT);
    rt_pin_mode(LCD_CS_PIN, PIN_MODE_OUTPUT);
    rt_pin_mode(LCD_BLK_PIN, PIN_MODE_OUTPUT);

    // 默认状态
    rt_pin_write(LCD_SCL_PIN, PIN_HIGH);
    rt_pin_write(LCD_SDA_PIN, PIN_HIGH);
    rt_pin_write(LCD_CS_PIN, PIN_HIGH);

    // 复位LCD
    rt_pin_write(LCD_RES_PIN, PIN_LOW);
    rt_thread_mdelay(100);
    rt_pin_write(LCD_RES_PIN, PIN_HIGH);
    rt_thread_mdelay(100);

    // 发送初始化命令
    const uint8_t *cmd = init_cmds;
    for (int i = 0; i < sizeof(init_cmds); ) {
        uint8_t count = cmd[i+1];
        if (count == 0x80) {  // 延时命令
            rt_thread_mdelay(cmd[i+2]);
            i += 3;
        } else {
            lcd_write_cmd(cmd[i]);
            for (uint8_t j = 0; j < count; j++) {
                lcd_write_data(cmd[i+2+j]);
            }
            i += (2 + count);
        }
    }

    // 设置显示方向 (0-3)
    lcd_set_orientation(0);

    // 开启背光
    rt_pin_write(LCD_BLK_PIN, PIN_LOW);
}

// 设置显示方向
void lcd_set_orientation(uint8_t orientation) {
    lcd_write_cmd(0x36);  // MADCTL命令

    switch (orientation % 4) {
    case 0:  // 纵向
        lcd_write_data(0x08);  // MY=0, MX=0, MV=0, ML=0, BGR=1
        break;
    case 1:  // 横向
        lcd_write_data(0x68);  // MY=0, MX=1, MV=1, ML=0, BGR=1
        break;
    case 2:  // 倒置纵向
        lcd_write_data(0xC8);  // MY=1, MX=1, MV=0, ML=0, BGR=1
        break;
    case 3:  // 倒置横向
        lcd_write_data(0xA8);  // MY=1, MX=0, MV=1, ML=0, BGR=1
        break;
    }
}

// 设置显示窗口
static void lcd_set_window(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) {
    // 设置列地址
    lcd_write_cmd(0x2A);
    lcd_write_data_16bit(x1 + LCD_X_OFFSET);
    lcd_write_data_16bit(x2 + LCD_X_OFFSET);

    // 设置行地址
    lcd_write_cmd(0x2B);
    lcd_write_data_16bit(y1 + LCD_Y_OFFSET);
    lcd_write_data_16bit(y2 + LCD_Y_OFFSET);

    // 写入RAM
    lcd_write_cmd(0x2C);
}

// 清屏
void lcd_clear(uint16_t color) {
    lcd_set_window(0, 0, LCD_WIDTH-1, LCD_HEIGHT-1);

    rt_pin_write(LCD_DC_PIN, PIN_HIGH);
    for (uint32_t i = 0; i < LCD_WIDTH * LCD_HEIGHT; i++) {
        lcd_spi_write_byte(color >> 8);
        lcd_spi_write_byte(color & 0xFF);
    }
}

// 绘制像素点
void lcd_draw_point(uint16_t x, uint16_t y, uint16_t color) {
    if (x >= LCD_WIDTH || y >= LCD_HEIGHT) return;

    lcd_set_window(x, y, x, y);
    lcd_write_data_16bit(color);
}

// 绘制矩形 (优化版)
void lcd_draw_rect(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color) {
    if (x1 >= LCD_WIDTH || y1 >= LCD_HEIGHT || x2 >= LCD_WIDTH || y2 >= LCD_HEIGHT) return;

    lcd_set_window(x1, y1, x2, y2);

    rt_pin_write(LCD_DC_PIN, PIN_HIGH);
    uint32_t size = (x2 - x1 + 1) * (y2 - y1 + 1);
    uint8_t high = color >> 8;
    uint8_t low = color & 0xFF;

    rt_pin_write(LCD_CS_PIN, PIN_LOW);
    for (uint32_t i = 0; i < size; i++) {
        lcd_spi_write_byte(high);
        lcd_spi_write_byte(low);
    }
    rt_pin_write(LCD_CS_PIN, PIN_HIGH);
}

// 显示字符 (8x16字体)
void lcd_show_char(uint16_t x, uint16_t y, char ch, uint16_t color, uint16_t bg_color) {
    if (x >= LCD_WIDTH - 8 || y >= LCD_HEIGHT - 16) return;

    lcd_set_window(x, y, x + 7, y + 15);

    rt_pin_write(LCD_DC_PIN, PIN_HIGH);
    rt_pin_write(LCD_CS_PIN, PIN_LOW);

    for (uint8_t i = 0; i < 16; i++) {
        uint8_t line = font8x16[ch * 16 + i];
        for (uint8_t j = 0; j < 8; j++) {
            uint16_t pixel_color = (line & (0x80 >> j)) ? color : bg_color;
            lcd_spi_write_byte(pixel_color >> 8);
            lcd_spi_write_byte(pixel_color & 0xFF);
        }
    }

    rt_pin_write(LCD_CS_PIN, PIN_HIGH);
}

// 显示字符串
void lcd_show_string(uint16_t x, uint16_t y, const char *str, uint16_t color, uint16_t bg_color) {
    while (*str) {
        lcd_show_char(x, y, *str++, color, bg_color);
        x += 8;
        if (x >= LCD_WIDTH - 8) {
            x = 0;
            y += 16;
            if (y >= LCD_HEIGHT - 16) break;
        }
    }
}

// 初始化LCD驱动
int lcd_driver_init(void) {
    lcd_init();
    // 开启背光
    rt_pin_write(LCD_BLK_PIN, PIN_LOW);

    rt_kprintf("ST7735S LCD (GPIO SPI) initialized\n");

    // 测试显示
    lcd_clear(COLOR_BLACK);
    lcd_show_string(0, 0, "GPIO SPI Mode", COLOR_GREEN, COLOR_BLACK);
    lcd_show_string(0, 16, "ST7735S 0.96\"", COLOR_WHITE, COLOR_BLACK);
    lcd_show_string(0, 32, "80x160 RGB565", COLOR_RED, COLOR_BLACK);

    return RT_EOK;
}

// 导出到自动初始化
INIT_APP_EXPORT(lcd_driver_init);
